<template>
  <div
    ref="editTableWrapper"
    class="editTableWrapper"
    @click="tableClick"
    @contextmenu="handleContext">

    <div v-if="showTable" class="tabletree-page" v-bind:style="{ height: detailHeight+tabletreeLowerHight + 'px', width: detailWidth+tabletreeWidth + 'px' }">
      <div class="tabletree-top" v-bind:style="{ height: detailHeight + 'px', width: detailWidth+tabletreeWidth + 'px' }">
        <div  v-if="legendReady  " class="legend" v-bind:style="{width:detailWidth+'px'}">
          <div>图例</div>
          <ul >
            <li v-for="(item,index) in legend" :key="index">
              <img :src="'statics/images/sysml/'+ item.icon+'.svg'"> {{ item.name }}
            </li>
          </ul>
        </div>
        <row-head
          ref="rowhead"
          class="fix north__east-bottom"
          :allRow="false"
          v-bind:style="{ left: (detailWidth+1) + 'px'}"
        >
        </row-head>
      </div>
      <div
        ref='tabletree_resize_v'
        class="tabletree-resize-v"
        @mouseover="mouseover(true)"
        @mouseleave="mouseleave(true)" ></div>
      <div class="tabletree-box" :style="{height:tabletreeLowerHight+'px'}">
        <div class="tabletree-left" v-bind:style="{ width: detailWidth + 'px' ,height:'100%'}">
          <col-head
            ref="colhead"
            class="fix south__west"
          >

          </col-head>
        </div>
        <div ref='tabletree_resize_h' class="tabletree-resize-h"   @mouseover="mouseover(false)" @mouseleave="mouseleave(false)"></div>
        <div class="tabletree-right" >
          <!-- 表体数值部分   右下角 -->
          <value-table

            ref="valuetable"
            :style="rightBottomStyle"
            :tableData.sync="tableData"
          >
          </value-table>
        </div>
        <br style="clear:both;">
      </div>

    </div>

    <div v-if="showTable==false" class="notabledata">
      <img src="statics/images/mainpage/imgnodata.svg" />
      <div class="nodata-text">当前范围暂无可用数据</div>
    </div>

  </div>
</template>
<script>
import ColHead from "./ColHead.vue";
import RowHead from "./RowHead.vue";
import ValueTable from "./ValueTable.vue";
import { ContextMenu } from 'src/components/common/ContextMenu/index';
import treeUtil from 'src/components/ModelTree/treeUtil';
import { graphHelper } from 'src/api/GraphHelper';
import { GraphNodeStatus } from 'src/constants/Enums';
import { cloneDeep } from 'lodash';

export const menuConfig = [

  {
    label: '创建关系',
    value: 'addRelation',
    icon: "",
    children: [
      { label: '出去方向', value: 'Outgoing', disabled: false, children: [] },
      { label: '进来方向', value: 'Incoming', disabled: false, children: [] }
    ]
  }
];

/**
 * 展开树形结构数据
 */
const getAllColumns = columns => {
  const result = [];
  columns.forEach(column => {
    if (column.children && column.children.length > 0) {
      result.push(column);
      result.push.apply(result, getAllColumns(column.children));
    } else {
      result.push(column);
    }
  });
  return result;
};
/**
 * 获得竖向表头的colspan和rowspan
 * 并且拿到竖向表头的数组
 */
const convertToRows = originColumns => {

  let maxLevel = 1;
  const traverse = (column, parent) => {
    if (parent) {
      column.level = parent.level + 1;
      if (maxLevel < column.level) {
        maxLevel = column.level;
      }
    }
    if (column.children && column.children.length > 0) {
      let colSpan = 0;
      column.children.forEach(subColumn => {
        traverse(subColumn, column);
        colSpan += subColumn.colSpan;
      });
      column.colSpan = colSpan;
    } else {
      column.colSpan = 1;
    }
  };

  originColumns.forEach(column => {
    column.level = 1;
    traverse(column);
  });
  const rows = [];
  for (let i = 0; i < maxLevel; i++) {
    rows.push([]);
  }
  const allColumns = getAllColumns(originColumns);

  allColumns.forEach(column => {
    if (!(column.children && column.children.length > 0)) {
      column.rowSpan = maxLevel - column.level + 1;
    } else {
      column.rowSpan = 1;
    }
    rows[column.level - 1].push(column);
  });

  let count = 0;
  let colRow = [];
  let lastData = [];
  let cell = [];
  for (let i = 0; i < maxLevel; i++) {
    cell.push(null);
  }
  allColumns.forEach(column => {
    let newCell = cloneDeep(cell);
    if (column.level === maxLevel || !(column.children && column.children.length > 0)) {
      colRow[count] = newCell;
      count++;
    }
  });

  let colRowIndex = 0;
  allColumns.forEach(column => {
    if (column.level === maxLevel || !(column.children && column.children.length > 0)) {
      colRow[colRowIndex][column.level - 1] = column;
      lastData.push(column);
      colRowIndex++;
    } else {
      colRow[colRowIndex][column.level - 1] = column;
    }
  });
  return { colRow: colRow, lastData: lastData };
};

//// 计算单元格的colSpan
/**
 * 计算单元格的colsapn，用于合并列
 * 计算单元格所属的层级
 * @param {*} originColumns，是指第一层级的元素
 */
const headersToRows = originColumns => {
  let maxLevel = 1;
  const traverse = (column, parent) => {
    if (parent) {
      //// 计算当前元素属于第几个层级
      column.level = parent.level + 1;
      if (maxLevel < column.level) {
        //// 计算最大层级
        maxLevel = column.level;
      }
    }
    if (column.children && column.children.length > 0) {
      let colSpan = 0;
      column.children.forEach(subColumn => {
        //// 进行递归
        traverse(subColumn, column);
        colSpan += subColumn.colSpan;
      });
      column.colSpan = colSpan;
    } else {
      column.colSpan = 1;
    }
  };

  originColumns.forEach(column => {
    column.level = 1;
    traverse(column);
  });
  const rows = [];
  let lastData = [];
  for (let i = 0; i < maxLevel; i++) {
    rows.push([]);
  }
  const allColumns = getAllColumns(originColumns);
  allColumns.forEach(column => {
    if (!(column.children && column.children.length > 0)) {
      column.rowSpan = maxLevel - column.level + 1;
      lastData.push(column);
    } else {
      column.rowSpan = 1;
    }
    rows[column.level - 1].push(column);
  });
  return { rows: rows, lastData: lastData };
};

export default {
  name: 'more-tree-table',
  components: { RowHead, ColHead, ValueTable },
  props: {
    getDiagramFilter: { type: Function },
    getData: Object,
    colData: {
      type: Array,
      default() {
        return [];
      }
    },
    rowData: {
      type: Array,
      default() {
        return [];
      }
    },

    tableTdHeight: {
      type: Number,
      default: 32
    },
    headColWidth: {
      type: Number,
      default: 32
    },
    DiagramInfo: Object,
    MatrixFilter: Object,
    visible: Boolean
  },
  data() {
    return {
      count: 0,
      data: [],
      //// 初始化数据
      initTable: [],
      scrollX: 0,
      scrollY: 0,
      legendReady: false,
      clientWidth: 0,
      clientHeight: 0,
      tdHeight: [],
      tableClientX: 0,
      tableClientY: 0,
      actualAll: 0,
      cloneRowData: [],
      cloneColData: [],
      treeToggleRow: {},
      treeToggleCol: {},
      selectedHeadNode: null,
      selectedHeadX: null,
      selectedHeadY: null,
      tableObj: {},
      addRelation: 1,
      events: {
        'project-modified': this.handleModelUpdate,
        'filter-update': this.filterUpdate
      },
      detailWidth: 172,
      detailHeight: 172

    };
  },
  provide() {
    return {
      //// edit: { rowData: this.rowData, colData: this.colData, allHeadRow: this.allHeadRow, allColHeadRow: this.allColHeadRow, headColWidth: this.headColWidth, tableTdHeight: this.tableTdHeight, resetNewColHead: this.resetNewColHead, textAlign: this.textAlign, resetNewRowHead: this.resetNewRowHead, lastDataCol: this.lastDataCol, lastDataRow: this.lastDataRow }
      edit: this
    };
  },
  computed: {
    /**
     * 当是多项表头表格时，表格的数据为Object
     */
    tableData(){
      return this.tableObj.tableData;
    },
    legend(){
      //// let tmp = Object.keys(this.tableObj.legend).map(x => );
      return this.MatrixFilter.dependencyCriteria.filter(y => this.tableObj.legend[y.icon] );

    },

    //// 横向表头的初始化数据
    headers() {
      if (this.cloneRowData.length > 0) {
        return this.cloneRowData;
      } else {
        return [];
      }

    },
    //// 获得横向表头的数据
    resetRow() {
      return headersToRows(this.headers);
    },
    //// 横向表头  tr和td的数据
    resetNewRowHead() {
      let data = this.resetRow;
      return data.rows;
    },
    lastDataRow() {
      let data = this.resetRow;
      return data.lastData;
    },
    //// 获得横向头部分层的数组
    allHeadRow() {
      return this.resetNewRowHead ? this.resetNewRowHead : [];
    },
    //// 获得横向头部最后一行的数组
    actualFields() {
      return this.lastDataRow;
    },
    //// 纵向表头初始化数据
    colHead() {
      if (this.cloneColData.length > 0) {
        let data = this.cloneColData;
        return data;
      } else {

        return [];
      }
    },
    //// 纵向表头分层数据
    allColHeadRow() {
      return this.resetNewColHead[0] ? this.resetNewColHead[0] : [];
    },
    //// 纵向表头最后一行的数据
    colActualFields() {
      return this.lastDataCol;
    },
    //// 横向表格的宽度
    colheadWidth() {

      return 172;
    },
    //// 纵向表头tr 和td的数据
    resetCol() {
      return convertToRows(this.colHead);
    },
    resetNewColHead() {
      let colRowData = this.resetCol;
      return colRowData.colRow;
    },
    lastDataCol() {
      let colRowData = this.resetCol;
      return colRowData.lastData;
    },
    //// 横向表头的高度
    headerHeight() {
      let height = this.allHeadRow.map(() => this.tableTdHeight).reduce((total, current) => total + current);
      return height;
    },
    tabletreeWidth(){
      return  this.lastDataRow.length * 32;
    },
    tabletreeLowerHight(){
      return  this.lastDataCol.length * 32;
    },
    actualWidth() {
      let width = 0;
      //// if (this.headers.length > 0) {
      if (this.lastDataRow.length > 0){
        width = this.lastDataRow.map(() => this.headColWidth).reduce((total, current) => total + current);
      } else {
        width = 0;
      }
      width = width + this.colheadWidth + this.allColHeadRow.length;
      return width;
    },
    actualWidth1() {
      let width = 0;
      //// if (this.headers.length > 0) {
      if (this.lastDataRow.length > 0){
        width = this.lastDataRow.map(() => this.headColWidth).reduce((total, current) => total + current);
      } else {
        width = 0;
      }
      return width;
    },

    editTableStyle() {
      return {
        height: "100%"
      };
    },
    //// 左上角
    northWestStyle() {
      return {
        width: this.colheadWidth + "px",
        //// height: this.tableHeaderHeight + "px"
      };
    },
    //// 左下角
    southWestStyle() {
      //// return { top: -this.scrollY + "px", width: this.colheadWidth + "px", left: "0px" };
      return { top: "0px", left: "0px" };
    },

    //// 右下角
    rightBottomStyle() {
      return {
        //// minWidth: "100%",
        width: "100%",
        position: "relative",

      };
    },
    showTable(){
      return this.cloneRowData.length > 0 && this.cloneColData.length > 0;
    }
  },
  watch: {
    //// visible: {      
    ////   immediate: false,  
    ////   handler(bool){
    ////     if (bool){
    ////       console.log(888);
    ////     //// this.handleFreshGraph();
    ////     }
    ////   }

    //// }
    visible(bool) {
      if ( bool){
        if (this.legendReady ){
          console.log('切换tab的刷新');
          this.reloadTable();
        } else {
          console.log('not ready');
        }
        
      }
      
    }
    //// MatrixFilter: {
    ////   immediate: true,
    ////   deep: true,
    ////   handler(val) {

    ////   }
    //// }
  },
  beforeDestroy(){
    this.$bus.offBatch(this.events);
  },
  updated(){
    if (this.showTable){
      this.dragControllerDiv(false, this.$refs.tabletree_resize_h);
      this.dragControllerDiv(true,  this.$refs.tabletree_resize_v);
    }
  },
  mounted() {
    this.$bus.onBatch(this.events);

    this.reloadTable(true);

    this.heightAdaption();

  },
  //// beforeUpdate(){ console.time('treeTableUpdate'); },
  //// updated(){ console.timeEnd('treeTableUpdate'); },
  methods: {
    mouseover(vertical){
      if (vertical){
        this.$refs.tabletree_resize_v.style.height = '3px';
      } else {
        this.$refs.tabletree_resize_h.style.width = '3px';
      }
    },
    mouseleave(vertical){
      if (vertical){
        this.$refs.tabletree_resize_v.style.height = '1px';
      } else {
        this.$refs.tabletree_resize_h.style.width = '1px';
      }
    },
    filterUpdate(val){
      if (!this.visible){
        return;
      }
      this.reloadTable();
      console.log(val);
      let filter = this.getDiagramFilter();
      //// let storage = filter.getMatrixStorage();
      //// console.log('----reload MatrixFilter', storage);
      filter.setMatrixStorage(JSON.stringify(val));

    },
    handleModelUpdate(){
      this.reloadTable();

    },
    reloadTable(mounted){
      if (this.visible === false){
        console.log('invisible');
        return;
      }
      //// console.time('treeTableUpdate');
      console.time('tongji');
      console.log('treeTableUpdate');

      //// rowScope 节点id  树形过滤
      //// 不用显示的逻辑 =>1 末节点 ，不在范围内 2 ，非末节点不在范围内 ，且子节点不含有需要显示的节点，子节点可以搜索完成
      //// 如果父节点需要显示 子节点不在范围 规则如何?? 只显示在范围内的子节点
      //// 1 自身在范围 或者子节点在范围
      //// 在当前场景下进行验证
      //// 未来数据构造是否需要改造??
      //// tree的scope 1 key in  treeKeyArray  key作为根节点过滤
      console.time('reload');
      //// console.time('stats');
      let  {  stats } = treeUtil.getExistingRelation(this.MatrixFilter);
      //// console.timeEnd('stats');
      //// console.time('getParentids');
      //// todo 拆分
      stats.withRelationIds.rowIds = stats.withRelationIds.row.map(x => x.id);
      stats.withRelationIds.colIds = stats.withRelationIds.col.map(x => x.id);
      //// 存在关系的父节点列表
      stats.withRelationIds.rowParents = this.getParentIds(stats.withRelationIds.row);
      stats.withRelationIds.colParents = this.getParentIds(stats.withRelationIds.col);
      ////

      //// console.timeEnd('getParentids');
      //// console.time('deepclone');

      //// 获取独立的节点关系 去重 如果scope中有包含关系 则子节点忽略 最后返回的十独立子节点

      let getTopNodes = (y) => {
        //// this.MatrixFilter.rowScope.map(x => x.key),
        let topNodes = [];

        y.forEach((a, b) => {
          let resetIds = y.slice(b + 1, y.length);
          let parentIds = this.getModelParentIds(a);
          if (parentIds.filter(c => resetIds.includes(c)).length > 0){
            console.log('不是独立节点', a);
          } else {
            //// console.log('独立节点', a, y);
            topNodes.push(a);
          }

        });
        return topNodes;
      };

      let zhedie = (x, folder) => {
        if (x == null) return;

        if (folder[x.id] ){
          x.children = [];
        }
        x.children.forEach(y => {
          zhedie(y, folder);
        });
      };
      console.time('折叠');

      let tmpDataArray = [];
      let tmpData1Array = [];

      let realCol = [];
      console.time('findeRealNode');
      this.MatrixFilter.colScope.forEach(x => {
        const node = graphHelper.getGraphNodeById(x, app.activeProjectId);
        if (node){
          realCol.push(node);
        } else {
          console.log('此节点可能已经删除');
        }
      });
      let realRow = [];
      this.MatrixFilter.rowScope.forEach(x => {
        const node = graphHelper.getGraphNodeById(x, app.activeProjectId);
        if (node){
          realRow.push(node);
        } else {
          console.log('此节点可能已经删除');
        }
      });
      console.timeEnd('findeRealNode');
      console.time('top1');
      getTopNodes(realCol).forEach(x => {
        //// console.log(x.disabled);
        //// if (x.disabled === true) return;
        if (treeUtil.isProfile(x)) return;
        let tmp = x;
        let tmpData = this.tableFilter(
          tmp,
          this.MatrixFilter.rowType.map(x => x.value),
          this.MatrixFilter.removedNodes.filter(x => x.datatype === 'row').map(x => x.key),
          stats,
          true
        );
        console.timeEnd('top1');
        if (tmpData){
          if (this.MatrixFilter.swapStatus){
            zhedie(tmpData, this.treeToggleCol);
          } else {
            zhedie(tmpData, this.treeToggleRow);
          }

          tmpDataArray.push(tmpData);
        }

      });
      
      console.time('top2');
      getTopNodes(realRow).forEach(x => {
        //// console.log(x.disabled);
        if (treeUtil.isProfile(x)) return;
        let tmp1 = x;
        let tmpData1 = this.tableFilter(
          tmp1,
          this.MatrixFilter.colType.map(x => x.value),
          this.MatrixFilter.removedNodes.filter(x => x.datatype === 'col').map(x => x.key),
          stats,
          false
        );
        if (tmpData1){
          if (this.MatrixFilter.swapStatus){
            zhedie(tmpData1, this.treeToggleRow);
          } else {
            zhedie(tmpData1, this.treeToggleCol);
          }

          tmpData1Array.push(tmpData1);
        }
      });
      console.timeEnd('top2');
      console.timeEnd('折叠');
      if (this.MatrixFilter.swapStatus){

        this.cloneColData = tmpDataArray;
        this.cloneRowData = tmpData1Array;
      } else {
        this.cloneRowData = tmpDataArray;
        this.cloneColData = tmpData1Array;
      }

      console.time('getRelation');
      //// 这里行列计算是否反了??
      this.tableObj =    treeUtil.getRelationMatrix(this.lastDataCol, this.lastDataRow, this.MatrixFilter);
      console.timeEnd('getRelation');
      console.timeEnd('reload');
      this.legendReady = true;
      //// topbar初始状态
      if (mounted){
        this.$parent.$refs.topbar.MatrixFilter = this.MatrixFilter;
        this.$parent.$refs.topbar.showContent = true;
      }

      //// this.$refs.valuetable.resetCross();
      //// this.$refs.editTableWrapper
      //// 90%时间还是在生成这个getRelation n*n的矩阵上 矩阵生成 99%的时间是在生成每个元素的可创建列表上
      this.clearSelection();
    },
    getModelParentIds(model){ //// 给一组id 得到他们的去重父节点列表
      let parents = [model.id];
      const findParents = (x) => {
        //// console.log(x.id);
        let o = x.container;
        if (parents.includes(x.id) === false){
          parents.push(x.id);
        }
        if (x.id === app.sysmlModel.id){
          //// console.log('root 终止');
        } else {
          if (o){
            findParents(o);
          }
        }
      };

      findParents(model);

      //// console.log('父节点列表 ', parents);
      return parents;
    },
    getParentIds(models){ //// 给一组id 得到他们的去重父节点列表
      let parents = models.map(x => x.id);
      const findParents = (x) => {
        //// console.log(x.id);
        let o = x.container;
        if (parents.includes(x.id) === false){
          parents.push(x.id);
        }
        if (x.id ===  app.sysmlModel.id){
          //// console.log('root 终止');
        } else {
          if (o){
            findParents(o);
          }
        }
      };
      models.forEach(element => {
        findParents(element);
      });
      //// console.log('父节点列表 ', parents);
      return parents;
    },
    tableFilter(obj,   filter = [],  removedNodesFilter = [], stats, isCol){ //// removedNodesFilter =>图中移出
      //// 影响表的内容 {方向过滤 关系类型过滤}  影响表的范围{行范围 列范围  行类型 列类型 =>观察对parent影响 => rowtype可以选element 作为全局  所以这里有个综合判定显示逻辑}
      if (treeUtil.isProfile(obj)) return null;
      //// let filter = { dicrection: ['RowToCol'], relationType: [],colScope: [], rowScope: [], colType: [], rowType: [] };
      let node = {};
      let folerNode = { isFolder: true };

      //// if (obj.hasOwnProperty('scopedSlots') && obj.hasOwnProperty('compartments')){
      let keys = ['id', 'children',  'incoming', 'outGoing', 'container', 'iconPath', 'displayTitle', 'baseConfig'];
      //// if (obj.hasOwnProperty('displayTitle') == false)console.log('-----99999', obj);
      for (let key of keys){
        switch (key) {
          case 'id':
            node['key'] = obj[key];
            node[key] = obj[key];
            folerNode[key] = obj[key];
            break;        
          case 'children':
            node.children = [];
            //// 是展开的，默认为null 所以默认展开
            //// 有子节点            
            obj.children.forEach(subColumn => {
              let subNode = this.tableFilter(subColumn, filter,  removedNodesFilter, stats, isCol);
              if (subNode != null){
                node.children.push(subNode);
              }
            });
            
            break;
          default:
            try {
              node[key] = obj[key];
              folerNode[key] = obj[key];
            } catch (error) {
              node[key] = '';
              folerNode[key] = '';
              console.log({ error });
            }
            break;
        }
        
      }
      node['typeName'] = obj.getTypeName();
      folerNode['typeName'] = node['typeName'];
      //// }
      //// 第一个节点输出
      //// treePath 可以让选中节点的子节点被复制  而选中节点的父节点需要单独计算
      //// 属于选中的子节点
      //// 属于选中的父节点
      //// let inParentScope = parentScope.includes(obj.id);
      //// console.log('inSubScope , inParentScope', inSubScope, inParentScope);

      //// 关系过滤
      let relationCriteria = true;
      //// emptyFilterType =>0 全部显示 1  非空矩阵 2 空矩阵 3 行为空矩阵 4 列为空矩阵
      if (this.MatrixFilter.emptyFilterType === 0){
        //// console.log('全部显示');
        relationCriteria = true;
      } else if (this.MatrixFilter.emptyFilterType === 1){
        if (isCol){
          //// 关系节点 or 父节点存在关系
          relationCriteria = stats.withRelationIds.colIds.includes(obj.id) || stats.withRelationIds.colParents.includes(obj.id);
        } else {
          relationCriteria = stats.withRelationIds.rowIds.includes(obj.id) || stats.withRelationIds.rowParents.includes(obj.id);
        }
        console.log('非空矩阵 显示所有有关系的节点及其父节点 relationCriteria:', relationCriteria);

      } else if (this.MatrixFilter.emptyFilterType === 2){
        console.log('空矩阵');
        if (isCol){
          //// 无关系节点
          relationCriteria = stats.withRelationIds.colIds.includes(obj.id) === false;
        } else {
          relationCriteria = stats.withRelationIds.rowIds.includes(obj.id) === false;
        }

      } else if (this.MatrixFilter.emptyFilterType === 3){
        if (isCol === false){
          console.log('行为空矩阵');
          relationCriteria = stats.withRelationIds.colIds.includes(obj.id) === false;
        }
      } else if (this.MatrixFilter.emptyFilterType === 4){
        if (isCol){
          relationCriteria = stats.withRelationIds.rowIds.includes(obj.id) === false;
          console.log('列为空矩阵', relationCriteria, obj.id);
        }
      }

      //// element 作为全局过滤条件
      //// 任意条件 : 1 当前元素类型在范围   2 子元素在范围 引发children.length>0
      let inType = filter.includes(obj.getTypeName()) || filter.includes('Element');
      
      //// console.log({ removedNodesFilter, obj });
      let notRemoveNodes = removedNodesFilter.includes(obj.id) === false;
      let hasChildren = node.children.length > 0 && notRemoveNodes;
      //// 具备子节点的 主动构造文件目录节点
      if (hasChildren){
        folerNode['children'] = [];
        node.children = [folerNode, ...node.children];
      }

      let isrelation = obj.getTypeName() === 'Relations';
      //// console.log('在范围内，元素类型过滤', inScope, '--', inType, obj.id, 'node.children.length ', node.children.length, 'relation 过滤 ', isrelation);
      //// 末端节点,展现则
      //// console.log(modelApi.getModelTypeName(obj.model));
      if ((hasChildren || inType)  && isrelation === false && notRemoveNodes && relationCriteria){
        //// console.log('当前节点符合规则', obj.id);
        return node;
      } else {
        //// console.log('当前节点不符合规则', { hasChildren, inType, isrelation, notRemoveNodes, relationCriteria });
        return null;
      }

    },
    clearSelection(){
      //// reload时 清除各种选中状态
      if (this.selectedHeadX != null || this.selectedHeadY != null){
        console.log('clear selection');
        this.$refs.valuetable.resetCross();
        this.$refs.editTableWrapper.querySelectorAll('.headtable .treeCellHighlight').forEach(item => {
          item.classList.toggle('treeCellHighlight');
        });
        this.selectedHeadX = null;
        this.selectedHeadY = null;
      }

    },
    handleContext(event) {
      this.$refs.valuetable.resetCross();
      //// 如果当前的矩阵未检入，则无法编辑
      const node = graphHelper.getGraphNodeById(app.ui.activeTabId, app.activeProjectId);
      if (app.activeProject.config.online && node.status !== GraphNodeStatus.CHECKED_IN) return;

      console.log({ x: event.clientX, y: event.clientY });
      let td;

      //// 多级搜索找到正确的td
      [event.target, event.target.parentNode, event.target.parentNode.parentNode, event.target.parentNode.parentNode.parentNode, event.target.parentNode.parentNode.parentNode.parentNode].forEach(x => {
        if (x.tagName === 'TD'){
          td = x;
        }
      });
      if (td === undefined) return;
      let key = td.dataset.key;
      if (this.tableData[key].disabled){
        console.log('disabled');
        return;
      } else {

      }

      menuConfig[0].children[0].children = this.tableData[key].relationOut.map(x => Object.assign(x, { direction: 'Out', icon: 'statics/images/sysml/' + x + '.svg', label: this.MatrixFilter.dependencyCriteria.find(y => y.icon === x).name, value: x, key: x }));
      menuConfig[0].children[1].children = this.tableData[key].relationIn.map(x =>  Object.assign(x, { direction: 'In', icon: 'statics/images/sysml/' + x + '.svg', label: this.MatrixFilter.dependencyCriteria.find(y => y.icon === x).name, value: x, key: x }));
      ContextMenu.popup({
        x: event.clientX,
        y: event.clientY,
        menuItems: menuConfig,
        getPortal: (i) => this.contextMenu = i
      }).then((res) => {
        console.log({ res });
        if (res.key === undefined) return;
        //// 创建关系
        //// this[menuItem.method] && this[menuItem.method](event, menuItem);
        let yindex = parseInt(td.dataset.yindex);
        let xindex = parseInt(td.dataset.xindex);
        //// console.log(this.lastDataRow[yindex], this.lastDataRow);

        let { existingRelationMatrix } = treeUtil.getExistingRelation(this.MatrixFilter);
        let combineKey = this.lastDataRow[yindex].id + '__' + this.lastDataRow[xindex].id;
        let sameRelation = existingRelationMatrix[combineKey];
        if (sameRelation){
          sameRelation = sameRelation.filter(combine => combine.stereotype === res.key);
          console.log(sameRelation);
          if (sameRelation.length > 0){
            this.$Confirm.popup({
              title: '重复创建关系',
              subTitle: `不允许重复创建同类关系`,
              content: ``,
              explain: ``,
              status: 'warn'
            }).then(() => {

            }).catch((e) => {

            });
            return;
          }
        }

        //// 这里的行列要作对
        //// model本身可以创建关系??
        let source;
        let target;
        if (this.lastDataRow[yindex].id === app.sysmlModel.id){
          source = app.sysmlModel;
        } else {
          source =  graphHelper.getGraphNodeById(this.lastDataRow[yindex].id, app.activeProjectId);

        }
        if (this.lastDataCol[xindex].id === app.sysmlModel.id){
          target = app.sysmlModel;
        } else {
          target = graphHelper.getGraphNodeById(this.lastDataCol[xindex].id, app.activeProjectId);

        }

        if (source && target){
          //// 区分出去和进来 ，出去相当于csm的行到列 ，默认创建成对类似<--->  进来默认创建 --><--
          /*
              if (direction === 'OUTGOING'){
        graphNode.addChildEdge(typeName, graphNode, createdNode, app.activeProjectId);
      } else {
        graphNode.addChildEdge(typeName, createdNode, graphNode, app.activeProjectId);
      }
          */
          if (res.direction === 'Out'){

            source.addChildEdge(res.key,  target, source, app.activeProjectId);
          } else {

            source.addChildEdge(res.key, source, target, app.activeProjectId);
          }

        }

        //// console.log(relation, ' relation');
        app.$bus.emit('project-modified');
        treeUtil.updateRelation(this.lastDataCol, this.lastDataRow, this.MatrixFilter, this.tableObj.tableData );

      }).catch((e) => {
        console.log(e); 
      });
    },
    heightAdaption() {
      this.$nextTick(() => {
        this.allTableHeight =
          this.$refs.editTableWrapper && this.$refs.editTableWrapper.offsetHeight
            ? this.$refs.editTableWrapper.offsetHeight
            : 0;
        this.allTableWidth =
          this.$refs.editTableWrapper && this.$refs.editTableWrapper.offsetWidth
            ? this.$refs.editTableWrapper.offsetWidth
            : 0;

      });
    },
    tableClick(e){
      let thNode = null;
      [ e.target, e.target.parentNode, e.target.parentNode.parentNode, e.target.parentNode.parentNode].forEach(x => {
        if (x.tagName === 'TH'){
          thNode = x;
        }
      });
      if (thNode == null){
        console.log('外部点击');
        return;
      }

      if (this.selectedHeadX != null || this.selectedHeadY != null){
        console.log('clear selection');
        this.$refs.valuetable.resetCross();
      }

      /* 行选中 列选中 或者中间选中
         this.selectedHeadX = null;
        this.selectedHeadY = null;
      */

      //// 直接拿e.currentTarget
      if ( thNode.firstChild.classList.contains('rowCell') || thNode.firstChild.classList.contains('colCell')){
        let isRow = thNode.firstChild.classList.contains('rowCell');
        this.toggleRow(thNode.dataset.key, isRow);

      } else {

        //// todo 列，行选择
        if (thNode.classList.contains('treeCellHighlight')){

        } else {

          this.$refs.editTableWrapper.querySelectorAll('.editTableBlock .treeCellHighlight').forEach(item => {
            item.classList.toggle('treeCellHighlight');
          });
        }

        thNode.classList.toggle('treeCellHighlight');
        if (thNode.parentNode.parentNode.parentNode.classList.contains('south__west')){

          this.selectedHeadY = null;
          let clickedIndex = this.getTableIndex(thNode, !this.MatrixFilter.swapStatus);
          console.log('左下角点击', thNode.parentNode.rowIndex, { clickedIndex }, this.MatrixFilter.swapStatus);
          if (thNode.classList.contains('treeCellHighlight')){
            if (this.selectedHeadY !== thNode.dataset.key){
              //// this.$refs.valuetable.$refs.valuetable.querySelectorAll(`.treeCellHighlight`).forEach((item) => {
              ////   item.classList.toggle('treeCellHighlight');
              //// });
            }

            this.selectedHeadY = thNode.dataset.key;
          } else {
            this.selectedHeadY = null;
          }

          //// this.$refs.valuetable.$refs.valuetable.querySelectorAll(`tr:nth-child(${clickedIndex + 1})`).forEach((item) => {
          ////   item.classList.toggle('treeCellHighlight');
          //// });
        }
        if (thNode.parentNode.parentNode.parentNode.classList.contains('north__east-bottom')){

          let clickedIndex = this.getTableIndex(thNode, this.MatrixFilter.swapStatus);
          console.log('右上角点击', thNode.cellIndex, { clickedIndex });
          this.selectedHeadX = null;
          if (thNode.classList.contains('treeCellHighlight')){
            if (this.selectedHeadX !== thNode.dataset.key){
              //// this.$refs.valuetable.$refs.valuetable.querySelectorAll(`.treeCellHighlight`).forEach((item) => {
              ////   item.classList.toggle('treeCellHighlight');
              //// });
            }
            this.selectedHeadX = thNode.dataset.key;
          } else {
            this.selectedHeadX = null;
          }

          //// this.$refs.valuetable.$refs.valuetable.querySelectorAll(`td:nth-child(${clickedIndex + 1})`).forEach((item) => {
          ////   item.classList.toggle('treeCellHighlight');
          //// });
        }
      }

    },
    getTableIndex(node, row){
      let index = 0;
      if (row){
        this.lastDataRow.forEach((x, y) => {
          if (x.id === node.dataset.key){
            index = y;
          }
        });
      } else {
        this.lastDataCol.forEach((x, y) => {
          if (x.id === node.dataset.key){
            index = y;
          }
        });
      }
      return index;
    },
    dragControllerDiv(vertical = false, drag) {
      //// 保留this引用
      let data = this;
      drag.onmousedown = function(e) {
        //// 颜色改变提醒
        let startX = e.clientX;
        if (vertical){
          startX = e.clientY;
        }
        console.log(111);
        document.onmousemove = function(e) {
          console.log(333);
          //// 计算并应用位移量
          let endX = e.clientX;
          if (vertical){
            endX = e.clientY;
          }
          let moveLen = endX - startX;
          startX = endX;

          if (vertical){
            if (data.detailHeight + moveLen <= data.$refs.editTableWrapper.querySelector('.tabletree-top .headtable').offsetHeight + 1){
              data.detailHeight += moveLen;
            }
          } else {
            if (data.detailWidth + moveLen <= data.$refs.editTableWrapper.querySelector('.tabletree-left .headtable').offsetWidth + 1){
              data.detailWidth += moveLen;
            }
            
          }

        };
        document.onmouseup = function() {
          //// 宽度恢复
          console.log('宽度恢复');
          data.$refs.tabletree_resize_v.style.height = '1px';
          data.$refs.tabletree_resize_h.style.width = '1px';

          document.onmousemove = null;
          document.onmouseup = null;
        };

        return false;
      };
    },

    //// 横向树点击事件 自主数据的生成
    //// filter写在这里??
    toggleRow(toggleKey, isRow){
      //// let toggleTree = cloneDeep(isRow ? this.rowData : this.colData);
      if (isRow){
        this.treeToggleRow[toggleKey] = !this.treeToggleRow[toggleKey];
      } else {
        this.treeToggleCol[toggleKey] = !this.treeToggleCol[toggleKey];
      }
      this.reloadTable();
      //// console.log(this.treeToggleRow, this.treeToggleCol);

    },

    getParentTag(startTag) {
      let self = this;
      //// 传入标签是否是DOM对象
      if (!(startTag instanceof HTMLElement)) return;
      //// 父级标签是否是body,是着停止返回集合,反之继续
      if ("BODY" !== startTag.parentElement.nodeName) {
        if (startTag.parentElement.nodeName === "TD") {
          return startTag.parentElement;
        } else {
          if (startTag.parentElement.parentElement) {
            return self.getParentTag(startTag.parentElement);
          } else {
            return false;
          }
        }
        //// 再上一层寻找
      }
    }
  }
};
</script>
<style lang="scss">
.editTableWrapper {
  position: relative;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  overflow: auto;

  .err-div {
    position: absolute;
    top: 10px;
    height: 20px !important;
    line-height: 20px !important;
    background: rgba(245, 108, 108, 0.1);
    border: 1px solid rgba(245, 108, 108, 0.4);
    font-size: 12px;
    color: #f56c6c;
    z-index: 1000;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  table {
    table-layout: fixed;
  }
  th {
    background: #fff;
    color: rgba(0, 0, 0, 0.85);
    font-weight:normal;
  }
}

.editTable {
  position: relative;
  overflow: hidden;
  border-top: 0;
  background: #fff;
  .th-div {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    div {
      height: 100%;
      .el-input {
        height: 100%;
        width: 100%;
      }
      .el-select {
        width: 100%;
      }
    }
    .el-input__inner {
      height: 100%;
      line-height: 100%;
      border: 0;
      outline: 0;
      background: transparent;
      padding-left: 6px;
      padding-right: 15px;
    }
    .el-date-editor .el-input__inner {
      padding-left: 30px;
    }
    .el-range-separator {
      visibility: hidden;
    }
    .el-range-input {
      background: transparent;
    }
  }
}

.north__west {
  background: transparent;
  font-size: 12px;

  z-index: 113;
  th {
    //// background: #f0f2f5;
    background: #fff;
    font-size: 12px;

    z-index: 112;

  }
}
.south__west {
  th {
    //// background: #f0f2f5;
    background: #fff;
    font-size: 12px;
    z-index: 112;
  }
  td {
    font-size: 12px;
    //// color: #606266;
    background: #fff;
    //// white-space: nowrap;
    //// overflow: hidden;
    //// text-overflow: ellipsis;
    //// font-size: 11px;
    svg {
      width: 20px;
      height: 20px;
      vertical-align: middle;
    }
  }
}
.north__east {
  position: absolute;
  top: 0px;
  //// min-width: 100%;
  z-index: 110;
  font-size: 12px;
  th {
    background: #fff;
  }
}

.editTableBlock {
  user-select: none;
  position: absolute;
  border-collapse: collapse;
  padding: 0;
  background-color: #fff;
  th{
    box-sizing: border-box;
        border: 1px solid #D9D9D9;
  }
    td {
      box-sizing: border-box;
      border: 1px solid #D9D9D9;
      width: 32px;
      height: 32px;

    overflow: hidden;
    position:relative;
    font-size: 8px;
    img{
      //// width: 14px;
      position: absolute;
      top:10px;
      left: 10px;
    }
      .valueNumber{
      position: absolute;
      right: 1px;
      bottom: 0;
    }

  }
}

.treeCellHighlight {
  background-color:rgba(74,137, 255, 1) !important;
  .treeCellEnable{
    background-color:rgba(74,137, 255, 1) ;
  }
  .treeCellDisable{
    background-color:rgba(74,137, 255, 1) ;
  }
}
.treeCellSelectHighlight{
background-color: #0250E2 !important;
}

.treeCellDisable{
  //// background-color:  rgba(0, 0, 0, 0.25);
  background-color:  #E8E8E8;
}

.treeCellEnable{
  background-color: white;

}

.editTableWrapper {
  width: 100%;
  flex: 1 1 calc(100% - 32px);
  border: 1px solid #D9D9D9;
  .el-input--small {
    .el-input__inner {
      border-color: transparent;
      background: transparent;
      font-size: 12px;
      color: #606266;
      outline: 0;
    }
  }
}
.north__east-bottom{
  table{
        border-bottom: 0;

  }
  th {
    //// border-bottom: 0;
  }
}

.icon-ser {
  cursor: pointer;
}
.editTableWrapper .editTable .el-form-item--mini.el-form-item,
.el-form-item--small.el-form-item {
  margin-bottom: 0;
}
.editTableWrapper .el-form-item--small .el-form-item__error {
  z-index: 100;
}

.verticalCol{
margin: 0 auto;
line-height: 16px;
overflow: hidden;
display: flex;
flex-direction:column;
width: 32px;
align-items: center;
span{
width: 17px;
word-wrap: break-word;
writing-mode: vertical-rl;
overflow: hidden;
};
img{
  margin:5px 0 5px 0;
   height: 16px;
 }
}

.verticalRow{
margin: 0 auto;
line-height: 16px;
overflow: hidden;
display: flex;
flex-direction:column;
width: 32px;
min-height: 172px;
align-items: center;
span{
width: 17px;
word-wrap: break-word;
writing-mode: vertical-rl;
overflow: hidden;
};
img{
  margin:5px 0 5px 0;
   height: 16px;
 }
}

.horizontalCol{
overflow: hidden;
 display: flex;
 flex-direction:row;
 flex-wrap: nowrap;
 height: 32px;
 min-width: 172px;

 align-items: center;

span{
height: 17px
};
 img{
   margin:0 5px 0 5px;
   height: 16px;
 }

}

.horizontalRow{
overflow: hidden;
 display: flex;
////  line-height: 16px;
 flex-direction:row;
 flex-wrap: nowrap;
 height: 32px;
 align-items: center;
span{
 height: 17px;
overflow: hidden;
　text-overflow:ellipsis;
　　white-space: nowrap;
};
 img{
   margin:0 5px 0 5px;
   height: 16px;
 }

}

.colWapper{
    width: 180px;
    position: relative;
    height: 100%;
    background: transparent;
}
.editTableBlock th img{
width: 20px;
}
.legend{
  height:100%;
  overflow-y:auto;
  padding:6px 0 0 11px;
  font-size: 12px;
  color: rgba(0, 0, 0, 0.85);
  //// font-weight: 500;
  line-height: 20px;
  img{
    width:16px
  }
  ul{
    margin-top:5px;
    li{
      margin-top:5px;
    }
  }
}

.tabletree-page{
  height: auto;
  position: relative;
  overflow: hidden;
  margin: 8px;
  border: 1px solid #000000;
}
.tabletree-box {
  //// width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;
  display: flex;
}
.tabletree-top {
  //// width: 100%;
  min-width: 200px;
  //// height: 80px;
  //// background: #ffe0c6;
  display: flex;
}
.tabletree-left {
  //// height: 100%;
  ////  background: #ffc5c1;
   overflow: hidden;
  /* flex: 1; */
}

.tabletree-resize-h {
  width: 1px;
  height: 100%;
  cursor: col-resize;
  background: #000;
  z-index: 10;
}
.tabletree-resize-v{
  //// width: 100%;
  height: 1px;
  z-index: 10;
  cursor: row-resize;
   background: #000;
    position: absolute;
    left: 0;
    width: 100%;
}

.tabletree-right {
  height: 100%;

}

.notabledata{
////   width: 140px;
//// height: 22px;

padding-top: 133px;
display:flex;
align-items: center;
 justify-content: space-between;
 flex-direction: column;
 .nodata-text{
   margin-top:12px;
   color: #979797;
   font-size: 14px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #000000;
    line-height: 22px;
 }
}

</style>
